EQUIPSLOTS.PLAYER = "player" -- 定义一个新的装备槽类型 PLAYER
AddModRPCHandler("mymod", "player_container", function(inst)
    if not GLOBAL.TheWorld.ismastersim or not inst or not inst:IsValid() or inst:HasTag("playerghost") then
        return
    end
    -- 先获取player装备栏的装备，再搜索容器组件打开
    local equip = inst.components.inventory and inst.components.inventory:GetEquippedItem(EQUIPSLOTS.PLAYER)
    if equip and equip.components.container then
        if not equip.components.container:IsOpen() then
            equip.components.container:Open(inst)
        else
            equip.components.container:Close(inst)
        end
    end
end)
-- 在 modmain.lua 中添加
AddPlayerPostInit(function(inst)
    inst:DoTaskInTime(1, function()
        if inst.components.inventory ~= nil then
            -- 移除物品栏中的 player_container
            for k, v in pairs(inst.components.inventory.itemslots) do
                if v and v.prefab == "player_container" then
                    inst.components.inventory:RemoveItem(v, true):Remove()
                end
            end
            -- 检查装备栏是否已经有 player_container
            local equip = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.PLAYER)
            if not (equip and equip.prefab == "player_container") then
                local item = SpawnPrefab("player_container")
                if item ~= nil then
                    inst.components.inventory:Equip(item, EQUIPSLOTS.PLAYER)
                end
            end
        end
        TheInput:AddKeyDownHandler(KEY_R, function()
            local screen = TheFrontEnd:GetActiveScreen()
            local IsHUDActive = screen and screen.name == "HUD"
            if inst:IsValid() and IsHUDActive and ThePlayer.HUD and not ThePlayer.HUD:HasInputFocus() then
                SendModRPCToServer(MOD_RPC["mymod"]["player_container"])
            end
        end)
    end)
end)
----------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
-- 导入所需的模块
local ImageButton = require "widgets/imagebutton" -- 导入图像按钮模块
local Text = require "widgets/text"               -- 导入文本模块
local TextButton = require "widgets/textbutton"

-- 更新页面显示的函数
local function UpdatePageDisplay(self, container, widget)
    -- 只遍历实际存在的槽位，防止越界
    local inv_len = self.inv and #self.inv or 0
    for i = 1, inv_len do
        if math.ceil(i / widget.page_grid_num) == container.cur_page then
            self.inv[i]:Show()
        else
            self.inv[i]:Hide()
        end
    end
    -- 设置页码文本
    if self["page_text"] then
        self["page_text"]:SetString(container.cur_page .. '/' .. widget.max_page)
    end
    -- 强制刷新格子内容
    if self.Refresh then
        self:Refresh()
    elseif self.RefreshSlots then
        self:RefreshSlots()
    end
end

-- 创建翻页按钮的函数
local function CreatePageButton(self, container, widget, direction)
    -- 创建按钮
    local button = self:AddChild(ImageButton(
        'images/global_redux.xml',        -- 使用图纸资源
        'arrow2_' .. direction .. '.tex', -- 指向左或右箭头纹理
        'arrow2_' .. direction .. '.tex', -- 悬停纹理
        'arrow2_' .. direction .. '.tex', -- 按下纹理
        'arrow2_' .. direction .. '.tex', -- 弹起纹理
        'arrow2_' .. direction .. '.tex'  -- 默认纹理
    ))

    -- 计算按钮的位置偏移量
    local x_offset = direction == "right" and widget.page_btn_spacing or 0 -- 根据方向计算偏移
    -- 设置按钮位置
    button:SetPosition(widget.page_btn_x + x_offset, widget.page_btn_y)
    -- 设置按钮缩放
    button:SetScale(widget.page_btn_x_scale, widget.page_btn_y_scale)

    -- 设置按钮点击事件
    button:SetOnClick(function()
        -- 计算页码变化量
        local page_change = direction == "right" and 1 or -1                                  -- 根据方向变化页码
        -- 更新当前页码
        container.cur_page = math.clamp(container.cur_page + page_change, 1, widget.max_page) -- 限制页码在1至最大页之间
        -- 更新页面显示
        UpdatePageDisplay(self, container, widget)                                            -- 刷新显示状态
        -- 发送RPC请求到服务器
        SendModRPCToServer(GetModRPC("mymod", "container_switch_page"),
            container.cur_page, container) -- 同步当前页码到服务器
    end)

    -- 返回创建的按钮
    return button -- 返回按钮实例
end

-- 获取物品槽位的函数
local function GetItemSlot(item, container, widget, cur_page)
    -- 如果没有物品或未启用翻页功能，则返回nil
    if not item or not widget.enable_Page then return nil end

    local free_slot = nil -- 用于存储空闲槽位的变量
    -- 遍历所有槽位
    for i = 1, container:GetNumSlots() do
        -- 如果当前槽位在当前页中
        if math.ceil(i / widget.page_grid_num) == cur_page then
            local item_in_slot = container:GetItemInSlot(i) -- 获取指定槽位中的物品

            if item_in_slot then
                -- 如果槽位中的物品与要放置的物品相同且可以堆叠且未满，则返回该槽位
                if item_in_slot.prefab == item.prefab and
                    item_in_slot.replica.stackable and
                    not item_in_slot.replica.stackable:IsFull() then
                    return i -- 返回该槽位
                end
            else
                -- 记录第一个空闲槽位
                free_slot = free_slot and math.min(free_slot, i) or i
            end
        end
    end
    -- 返回第一个空闲槽位
    return free_slot -- 返回空闲槽位索引或nil
end

-- 修改 ContainerWidget
AddClassPostConstruct('widgets/containerwidget', function(self, ...)
    -- 保存旧的Open方法
    local old_Open = self.Open
    function self:Open(container, doer, ...)
        if old_Open then
            old_Open(self, container, doer, ...)
        end

        -- 兼容 player_container 的缩放
        if self.container and self.container.prefab and self.container.prefab == "player_container" and self.bganim ~= nil then
            self.bganim:SetScale(2.25, 2.25, 1)
        end

        --整理按钮，仅对 player_container 生效
        if self.container and self.container.prefab == "player_container" and not self.sort_btn then
            local widget = container.replica.container:GetWidget()
            -- 按钮位置在页码右侧偏移，字体更大
            local sort_btn_x = widget.page_text_x + 140
            local sort_btn_y = widget.page_text_y
            self.sort_btn = self:AddChild(TextButton())
            self.sort_btn:SetText("整理")
            self.sort_btn:SetTextSize(45)
            self.sort_btn:SetTextColour(1, 1, 0.5, 1)
            self.sort_btn:SetTextFocusColour(1, 1, 1, 1)
            self.sort_btn:SetPosition(sort_btn_x, sort_btn_y)
            -- 设置背景图片和透明度，和dragonflyfurnace一致
            self.sort_btn.image:SetTexture("images/global_redux.xml", "button_long.tex")
            self.sort_btn.image:Show()
            self.sort_btn.image:SetTint(1, 1, 1, 1) -- dragonflyfurnace是全白不透明
            self.sort_btn:SetOnClick(function()
                if container and container.components and container.components.container then
                    local slots = container.components.container.slots
                    local widget = container.replica.container:GetWidget()
                    local cur_page = container.cur_page or 1
                    local page_grid_num = widget.page_grid_num or #slots
                    local page_slots = {}
                    -- 收集当前页的物品
                    for k, v in pairs(slots) do
                        if math.ceil(k / page_grid_num) == cur_page and v then
                            table.insert(page_slots, v)
                        end
                    end
                    -- 合并同类物品
                    local prefab_map = {}
                    for _, item in ipairs(page_slots) do
                        local prefab = item.prefab
                        prefab_map[prefab] = prefab_map[prefab] or {}
                        table.insert(prefab_map[prefab], item)
                    end
                    -- 生成合并后的物品列表
                    local merged_items = {}
                    for prefab, items in pairs(prefab_map) do
                        local total = 0
                        for _, item in ipairs(items) do
                            if item.components.stackable then
                                total = total + item.components.stackable:StackSize()
                            else
                                total = total + 1
                            end
                        end
                        -- 只保留一个物品，堆叠数为总和
                        local merged = items[1]
                        if merged.components.stackable then
                            merged.components.stackable:SetStackSize(total)
                        end
                        table.insert(merged_items, merged)
                        -- 其余的移除
                        for i = 2, #items do
                            items[i]:Remove()
                        end
                    end
                    -- 按 prefab 排序
                    table.sort(merged_items, function(a, b) return a.prefab < b.prefab end)
                    -- 清空当前页
                    for k = 1, page_grid_num do
                        local slot = (cur_page - 1) * page_grid_num + k
                        slots[slot] = nil
                    end
                    -- 重新填充
                    for idx, item in ipairs(merged_items) do
                        local slot = (cur_page - 1) * page_grid_num + idx
                        slots[slot] = item
                    end
                    -- 强制刷新容器UI和同步
                    if container.components.container.Refresh then
                        container.components.container:Refresh()
                    end
                    if self and self.inv and widget then
                        UpdatePageDisplay(self, container, widget)
                    end
                elseif container and container.replica and container.replica.container and not container.replica.container:IsBusy() then
                    SendRPCToServer(RPC.DoWidgetButtonAction, nil, container, nil)
                end
            end)
        end

        -- 获取容器的widget配置
        local widget = container.replica.container:GetWidget()
        -- 如果容器或widget未启用翻页功能，则返回
        if not (container and widget and widget.enable_Page) then return end

        -- 如果未初始化翻页按钮
        if not self["page_btn_enable"] then
            -- 标记已初始化翻页按钮
            self["page_btn_enable"] = true
            -- 初始化当前页码
            container.cur_page = container.cur_page or 1

            -- 创建页码文本
            self["page_text"] = self:AddChild(Text(NUMBERFONT, 35,
                container.cur_page .. '/' .. widget.max_page)) -- 创建页码文本
            -- 设置页码文本位置
            self["page_text"]:SetPosition(widget.page_text_x, widget.page_text_y)

            -- 创建右翻页按钮
            self["page_btn_right"] = CreatePageButton(self, container, widget, "right")
            -- 创建左翻页按钮
            self["page_btn_left"] = CreatePageButton(self, container, widget, "left")

            -- 初始化显示
            UpdatePageDisplay(self, container, widget) -- 更新页面显示
        end
        -- 只注册一次
        if self.container and self.container.prefab == "player_container" and not self._drag_registered then
            self._drag_registered = true
            -- 让整个容器widget响应拖拽
            self.OnMouseButton = function(widget, button, down, x, y)
                if button == MOUSEBUTTON_RIGHT and down then
                    widget.draging = true
                    widget:FollowMouse()
                elseif button == MOUSEBUTTON_RIGHT then
                    widget.draging = false
                    widget:StopFollowMouse()
                end
            end
        end
    end
end)

-- 修改 ContainerReplica
AddClassPostConstruct('components/container_replica', function(self, ...)
    -- 保存旧的GetSpecificSlotForItem方法
    local old_GetSpecificSlotForItem = self.GetSpecificSlotForItem

    function self:GetSpecificSlotForItem(item, ...)
        -- 如果未使用特定槽位，则调用旧的方法
        if not self.usespecificslotsforitems then
            return old_GetSpecificSlotForItem and old_GetSpecificSlotForItem(self, item, ...)
        end
        -- 获取容器的widget配置
        local widget = self:GetWidget()
        -- 获取物品槽位
        return GetItemSlot(item, self, widget, self.inst.cur_page or 1) or
            (old_GetSpecificSlotForItem and old_GetSpecificSlotForItem(self, item, ...)) -- 返回槽位
    end
end)

-- 修改 Container 组件
AddComponentPostInit('container', function(self)
    -- 保存旧的GetSpecificSlotForItem方法
    local old_GetSpecificSlotForItem = self.GetSpecificSlotForItem

    function self:GetSpecificSlotForItem(item, ...)
        -- 如果未使用特定槽位，则调用旧的方法
        if not self.usespecificslotsforitems then
            return old_GetSpecificSlotForItem and old_GetSpecificSlotForItem(self, item, ...)
        end

        -- 获取容器的widget配置
        local widget = self:GetWidget()
        -- 获取物品槽位
        return GetItemSlot(item, self, widget, self.inst.cur_page or 1) or
            (old_GetSpecificSlotForItem and old_GetSpecificSlotForItem(self, item, ...)) -- 返回槽位
    end
end)

-- RPC 处理器
AddModRPCHandler("mymod", "container_switch_page", function(player, page, container)
    -- 如果容器和页码存在，则更新容器的当前页码
    if container and page then
        container.cur_page = page -- 更新当前页码
    end
end)
---------拖拽
local function ModFollowMouse(self)
    --GetWorldPosition获得的坐标是基于屏幕原点的，默认为左下角，当单独设置了原点坐标的时候，这个函数返回的结果和GetPosition的结果一样了，达不到我们需要的效果
    --因为官方没有提供查询原点坐标的接口，所以需要修改设置原点的两个函数，将原点位置记录在widget上
    --注意：虽然默认的屏幕原点为左下角，但是每个widget默认的坐标原点为其父级的屏幕坐标；
    --而当你单独设置了原点坐标后，不仅其屏幕原点改变了，而且坐标原点的位置也改变为屏幕原点了
    local old_sva = self.SetVAnchor
    self.SetVAnchor = function(_self, anchor)
        self.v_anchor = anchor
        return old_sva(_self, anchor)
    end

    local old_sha = self.SetHAnchor
    self.SetHAnchor = function(_self, anchor)
        self.h_anchor = anchor
        return old_sha(_self, anchor)
    end

    --默认的原点坐标为父级的坐标，如果widget上有v_anchor和h_anchor这两个变量，就说明改变了默认的原点坐标
    --我们会在GetMouseLocalPos函数里检查这两个变量，以对这种情况做专门的处理
    --这个函数可以将鼠标坐标从屏幕坐标系下转换到和wiget同一个坐标系下
    local function GetMouseLocalPos(ui, mouse_pos)                         --ui: 要拖拽的widget, mouse_pos: 鼠标的屏幕坐标(Vector3对象)
        local g_s = ui:GetScale()                                          --ui的全局缩放值
        local l_s = Vector3(0, 0, 0)
        l_s.x, l_s.y, l_s.z = ui:GetLooseScale()                           --ui本身的缩放值
        local scale = Vector3(g_s.x / l_s.x, g_s.y / l_s.y, g_s.z / l_s.z) --父级的全局缩放值

        local ui_local_pos = ui:GetPosition()                              --ui的相对位置（也就是SetPosition的时候传递的坐标）
        ui_local_pos = Vector3(ui_local_pos.x * scale.x, ui_local_pos.y * scale.y, ui_local_pos.z * scale.z)
        local ui_world_pos = ui:GetWorldPosition()
        --如果修改过ui的屏幕原点，就重新计算ui的屏幕坐标（基于左下角为原点的）
        if not (not ui.v_anchor or ui.v_anchor == ANCHOR_BOTTOM) or not (not ui.h_anchor or ui.h_anchor == ANCHOR_LEFT) then
            local screen_w, screen_h = TheSim:GetScreenSize()    --获取屏幕尺寸（宽度，高度）
            if ui.v_anchor and ui.v_anchor ~= ANCHOR_BOTTOM then --如果修改了原点的垂直坐标
                ui_world_pos.y = ui.v_anchor == ANCHOR_MIDDLE and screen_h / 2 + ui_world_pos.y or
                    screen_h - ui_world_pos.y
            end
            if ui.h_anchor and ui.h_anchor ~= ANCHOR_LEFT then --如果修改了原点的水平坐标
                ui_world_pos.x = ui.h_anchor == ANCHOR_MIDDLE and screen_w / 2 + ui_world_pos.x or
                    screen_w - ui_world_pos.x
            end
        end

        local origin_point = ui_world_pos - ui_local_pos --原点坐标
        mouse_pos = mouse_pos - origin_point

        return Vector3(mouse_pos.x / scale.x, mouse_pos.y / scale.y, mouse_pos.z / scale.z) --鼠标相对于UI父级坐标的局部坐标
    end

    --修改官方的鼠标跟随，以适应所有情况(垃圾科雷)
    self.FollowMouse = function(_self)
        if _self.followhandler == nil then
            _self.followhandler = TheInput:AddMoveHandler(function(x, y)
                local loc_pos = GetMouseLocalPos(_self, Vector3(x, y, 0)) --主要是将原本的x,y坐标进行了坐标系的转换，使用转换后的坐标来更新widget位置
                _self:UpdatePosition(loc_pos.x, loc_pos.y)
            end)
            _self:SetPosition(GetMouseLocalPos(_self, TheInput:GetScreenPosition()))
        end
    end
end
AddClassPostConstruct("widgets/widget", ModFollowMouse)
